﻿using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using WeatherHistory.Data.Entities;
using WeatherHistory.Shared.Helpers;

namespace WeatherHistory.Data;

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    public DbSet<Account> Accounts { get; set; }
    public DbSet<Region> Regions { get; set; }
    public DbSet<RegionType> RegionTypes { get; set; }
    public DbSet<Forecast> Forecasts { get; set; }
    public DbSet<Weather> Weathers { get; set; }
    public DbSet<WeatherForecastRelation> WeatherForecastRelations { get; set; }
    public DbSet<WeatherRegionRelation> WeatherRegionRelations { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        UpdateStructure(builder);
        SeedData(builder);

        base.OnModelCreating(builder);
    }

    private static void UpdateStructure(ModelBuilder builder)
    {
        builder.Entity<Region>()
            .HasOne(region => region.ParentRegion)
            .WithMany(parent => parent.ChildRegions)
            .HasForeignKey(region => region.ParentRegionId);

        builder.Entity<Region>()
            .HasOne(region => region.UpdatedBy)
            .WithMany(account => account.UpdatedRegions)
            .HasForeignKey(region => region.CreatedById)
            .OnDelete(DeleteBehavior.Cascade);

        builder.Entity<Region>()
            .HasOne(region => region.RegionType)
            .WithMany(regionType => regionType.Regions)
            .HasForeignKey(region => region.RegionTypeId);

        builder.Entity<Forecast>()
            .HasOne(forecast => forecast.Region)
            .WithMany(region => region.Forecasts)
            .HasForeignKey(forecast => forecast.RegionId);

        builder.Entity<Forecast>()
            .HasMany(forecast => forecast.Weathers)
            .WithMany(weather => weather.Forecasts)
            .UsingEntity<WeatherForecastRelation>(
                relation => relation
                    .HasOne(weatherForecast => weatherForecast.Weather)
                    .WithMany(weather => weather.WeatherForecastRelations)
                    .HasForeignKey(weatherForecast => weatherForecast.WeatherId)
                    .OnDelete(DeleteBehavior.Cascade),
                relation => relation
                    .HasOne(weatherForecast => weatherForecast.Forecast)
                    .WithMany(forecast => forecast.WeatherForecastRelations)
                    .HasForeignKey(weatherForecast => weatherForecast.ForecastId)
                    .OnDelete(DeleteBehavior.Cascade),
                entity =>
                {
                    entity.Property(p => p.CreatedAt).HasDefaultValueSql("CURRENT_TIMESTAMP");
                    entity.HasKey(p => new { p.ForecastId, p.WeatherId });
                }
            );

        builder.Entity<Weather>()
            .HasMany(weather => weather.Regions)
            .WithMany(region => region.Weathers)
            .UsingEntity<WeatherRegionRelation>(
                relation => relation
                    .HasOne(weatherRegion => weatherRegion.Region)
                    .WithMany(region => region.WeatherRegionRelations)
                    .HasForeignKey(weatherRegion => weatherRegion.RegionId),
                relation => relation
                    .HasOne(weatherRegion => weatherRegion.Weather)
                    .WithMany(weather => weather.WeatherRegionRelations)
                    .HasForeignKey(weatherRegion => weatherRegion.WeatherId),
                entity =>
                {
                    entity.Property(p => p.CreatedAt).HasDefaultValueSql("CURRENT_TIMESTAMP");
                    entity.HasKey(p => new { p.RegionId, p.WeatherId });
                }
            );
    }

    private static void SeedData(ModelBuilder builder)
    {
        var accounts = new List<Account>
        {
            new Account
            {
                Id = 1,
                FirstName = "Generated",
                LastName = "Admin",
                Email = "admin@sber.ru",
                PasswordHash = SecurityHelper.ComputeSha256Hash("qwerty123")
            }
        };

        builder.Entity<Account>().HasData(accounts);
    }
}